﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Windows.ApplicationModel.Activation;
using Windows.ApplicationModel.Search;
using Windows.Foundation;
using Windows.Storage.Streams;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media.Imaging;

// Pour en savoir plus sur le modèle d'élément Contrat de recherche, consultez la page http://go.microsoft.com/fwlink/?LinkId=234240

namespace InterfaceXAML
{
    // TODO: modifiez le manifeste pour activer la recherche
    //
    // Impossible de mettre à jour automatiquement le manifeste de package.  Ouvrez le fichier du manifeste de package,
    // puis vérifiez que la prise en charge de l'activation de la recherche est activée.
    /// <summary>
    /// Cette page affiche les résultats d'une recherche globale effectuée dans cette application.
    /// </summary>
    public sealed partial class SearchPage : InterfaceXAML.Common.LayoutAwarePage
    {
        private UIElement _previousContent;
        private ApplicationExecutionState _previousExecutionState;

        public SearchPage()
        {
            this.InitializeComponent();
            searchPane = SearchPane.GetForCurrentView();
        }

        /// <summary>
        /// Determines how best to support navigation back to the previous application state.
        /// </summary>
        public static void Activate(String queryText, ApplicationExecutionState previousExecutionState)
        {
            var previousContent = Window.Current.Content;
            var frame = previousContent as Frame;

            if (frame != null)
            {
                // If the app is already running and uses top-level frame navigation we can just
                // navigate to the search results
                frame.Navigate(typeof(SearchPage), queryText);
            }
            else
            {
                // Otherwise bypass navigation and provide the tools needed to emulate the back stack
                SearchPage page = new SearchPage();
                page._previousContent = previousContent;
                page._previousExecutionState = previousExecutionState;
                page.LoadState(queryText, null);
                Window.Current.Content = page;
            }

            // Either way, active the window
            Window.Current.Activate();
        }

        /// <summary>
        /// Populates the page with content passed during navigation.  Any saved state is also
        /// provided when recreating a page from a prior session.
        /// </summary>
        /// <param name="navigationParameter">The parameter value passed to
        /// <see cref="Frame.Navigate(Type, Object)"/> when this page was initially requested.
        /// </param>
        /// <param name="pageState">A dictionary of state preserved by this page during an earlier
        /// session.  This will be null the first time a page is visited.</param>
        protected override void LoadState(Object navigationParameter, Dictionary<String, Object> pageState)
        {
            var queryText = navigationParameter as String;

            // TODO: Application-specific searching logic.  The search process is responsible for
            //       création d'une liste de catégories de résultats sélectionnables par l'utilisateur :
            //
            //       filterList.Add(new Filter("<filter name>", <result count>));
            //
            //       Seul le premier filtre (en général « Tout ») doit transmettre la valeur True comme troisième argument
            //       afin de démarrer avec l'état actif. Les résultats du filtre actif sont fournis
            //       dans Filter_SelectionChanged ci-dessous.

            var filterList = new List<Filter>();
            filterList.Add(new Filter("All", 0, true));

            // Communiquez les résultats via le modèle d'affichage
            this.DefaultViewModel["QueryText"] = '\u201c' + queryText + '\u201d';
            this.DefaultViewModel["CanGoBack"] = this._previousContent != null;
            this.DefaultViewModel["Filters"] = filterList;
            this.DefaultViewModel["ShowFilters"] = filterList.Count > 1;
        }

        /// <summary>
        /// Invoqué lorsqu'un utilisateur clique sur le bouton Précédent.
        /// </summary>
        /// <param name="sender">L'instance Button représentant le bouton Précédent.</param>
        /// <param name="e">Données d'événement décrivant la façon dont l'utilisateur a cliqué sur le bouton.</param>
        protected override void GoBack(object sender, RoutedEventArgs e)
        {
            // Retournez à l'état de l'application telle qu'elle était avant la requête de recherche
            if (this.Frame != null && this.Frame.CanGoBack)
            {
                this.Frame.GoBack();
            }
            else if (this._previousContent != null)
            {
                Window.Current.Content = this._previousContent;
            }
            else
            {
                // TODO: invoke the app's normal launch behavior, using this._previousExecutionState
                //       as appropriate.  Exact details can vary from app to app, which is why an
                //       implementation isn't included in the Search Contract template.  Typically
                //       this method and OnLaunched in App.xaml.cs can call a common method.
            }
        }

        /// <summary>
        /// Invoqué lorsqu'un filtre est sélectionné à l'aide d'un contrôle ComboBox avec l'état d'affichage Snapped.
        /// </summary>
        /// <param name="sender">Instance ComboBox.</param>
        /// <param name="e">Données d'événement décrivant la façon dont le filtre sélectionné a été modifié.</param>
        void Filter_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            // Déterminez quel filtre a été sélectionné
            var selectedFilter = e.AddedItems.FirstOrDefault() as Filter;
            if (selectedFilter != null)
            {
                // Reflétez les résultats dans l'objet Filter correspondant pour permettre à
                // la représentation RadioButton utilisée avec un état d'affichage autre que Snapped de refléter les modifications apportées
                selectedFilter.Active = true;

                // TODO: répondez à la modification du filtre actif en associant this.DefaultViewModel["Results"]
                //       to a collection of items with bindable Image, Title, Subtitle, and Description properties

                // Ensure results are found
                object results;
                ICollection resultsCollection;
                if (this.DefaultViewModel.TryGetValue("Results", out results) &&
                    (resultsCollection = results as ICollection) != null &&
                    resultsCollection.Count != 0)
                {
                    VisualStateManager.GoToState(this, "ResultsFound", true);
                    return;
                }
            }

            // Display informational text when there are no search results.
            VisualStateManager.GoToState(this, "NoResultsFound", true);
        }

        /// <summary>
        /// Invoqué lorsqu'un filtre est sélectionné à l'aide d'un RadioButton, lorsque l'état d'affichage n'est pas Snapped.
        /// </summary>
        /// <param name="sender">Instance RadioButton sélectionnée.</param>
        /// <param name="e">Données d'événement décrivant la façon dont le RadioButton a été sélectionné.</param>
        void Filter_Checked(object sender, RoutedEventArgs e)
        {
            // Reflétez la modification dans le CollectionViewSource utilisé par le contrôle ComboBox correspondant
            // pour garantir que la modification soit reflétée lorsque l'état d'affichage a la valeur Snapped
            if (filtersViewSource.View != null)
            {
                var filter = (sender as FrameworkElement).DataContext;
                filtersViewSource.View.MoveCurrentTo(filter);
            }
        }

        private SearchPane searchPane;

        private static readonly string[] suggestionList =
            {
                "Shanghai", "Istanbul", "Karachi", "Delhi", "Mumbai", "Moscow", "São Paulo", "Seoul", "Beijing", "Jakarta",
                "Tokyo", "Mexico City", "Kinshasa", "New York City", "Lagos", "London", "Lima", "Bogota", "Tehran", "Ho Chi Minh City",
                "Hong Kong", "Bangkok", "Dhaka", "Cairo", "Hanoi", "Rio de Janeiro", "Lahore", "Chonquing", "Bangalore", "Tianjin",
                "Baghdad", "Riyadh", "Singapore", "Santiago", "Saint Petersburg", "Surat", "Chennai", "Kolkata", "Yangon", "Guangzhou",
                "Alexandria", "Shenyang", "Hyderabad", "Ahmedabad", "Ankara", "Johannesburg", "Wuhan", "Los Angeles", "Yokohama",
                "Abidjan", "Busan", "Cape Town", "Durban", "Pune", "Jeddah", "Berlin", "Pyongyang", "Kanpur", "Madrid", "Jaipur",
                "Nairobi", "Chicago", "Houston", "Philadelphia", "Phoenix", "San Antonio", "San Diego", "Dallas", "San Jose",
                "Jacksonville", "Indianapolis", "San Francisco", "Austin", "Columbus", "Fort Worth", "Charlotte", "Detroit",
                "El Paso", "Memphis", "Baltimore", "Boston", "Seattle Washington", "Nashville", "Denver", "Louisville", "Milwaukee",
                "Portland", "Las Vegas", "Oklahoma City", "Albuquerque", "Tucson", "Fresno", "Sacramento", "Long Beach", "Kansas City",
                "Mesa", "Virginia Beach", "Atlanta", "Colorado Springs", "Omaha", "Raleigh", "Miami", "Cleveland", "Tulsa", "Oakland",
                "Minneapolis", "Wichita", "Arlington", " Bakersfield", "New Orleans", "Honolulu", "Anaheim", "Tampa", "Aurora",
                "Santa Ana", "St. Louis", "Pittsburgh", "Corpus Christi", "Riverside", "Cincinnati", "Lexington", "Anchorage",
                "Stockton", "Toledo", "St. Paul", "Newark", "Greensboro", "Buffalo", "Plano", "Lincoln", "Henderson", "Fort Wayne",
                "Jersey City", "St. Petersburg", "Chula Vista", "Norfolk", "Orlando", "Chandler", "Laredo", "Madison", "Winston-Salem",
                "Lubbock", "Baton Rouge", "Durham", "Garland", "Glendale", "Reno", "Hialeah", "Chesapeake", "Scottsdale",
                "North Las Vegas", "Irving", "Fremont", "Irvine", "Birmingham", "Rochester", "San Bernardino", "Spokane",
                "Toronto", "Montreal", "Vancouver", "Ottawa-Gatineau", "Calgary", "Edmonton", "Quebec City", "Winnipeg", "Hamilton"
            };


        private async void OnSearchPaneSuggestionsRequested(SearchPane sender, SearchPaneSuggestionsRequestedEventArgs e)
        {
            var queryText = e.QueryText;
            if (string.IsNullOrEmpty(queryText))
            {
                Debug.WriteLine("No query");
            }
            else
            {
                var request = e.Request;
                foreach (string suggestion in suggestionList)
                {
                    if (suggestion.StartsWith(queryText, StringComparison.CurrentCultureIgnoreCase))
                    {
                        // Add suggestion to Search Pane
                        request.SearchSuggestionCollection.AppendQuerySuggestion(suggestion);
                        request.SearchSuggestionCollection.AppendSearchSeparator("Recommendations");
                        request.SearchSuggestionCollection.AppendResultSuggestion(suggestion, 
                            "", 
                            "",
                            RandomAccessStreamReference.CreateFromUri(new Uri("http://i82.photobucket.com/albums/j249/roxy201/los-angeles.png")), 
                            "");

                        // Break since the Search Pane can show at most 5 suggestions
                        if (request.SearchSuggestionCollection.Size >= 5)
                        {
                            break;
                        }
                    }
                }

                if (request.SearchSuggestionCollection.Size > 0)
                {
                    Debug.WriteLine("Suggestions provided for query: " + queryText);
                }
                else
                {
                    Debug.WriteLine("No suggestions provided for query: " + queryText);
                }
            }
        }

        protected override void OnNavigatedTo(Windows.UI.Xaml.Navigation.NavigationEventArgs e)
        {
            base.OnNavigatedTo(e);
            /*searchPane.ResultSuggestionChosen
            searchPane.QuerySubmitted*/
            searchPane.SuggestionsRequested += new TypedEventHandler<SearchPane, SearchPaneSuggestionsRequestedEventArgs>(OnSearchPaneSuggestionsRequested);
        }

        protected override void OnNavigatedFrom(Windows.UI.Xaml.Navigation.NavigationEventArgs e)
        {
            base.OnNavigatedFrom(e);
            searchPane.SuggestionsRequested -= new TypedEventHandler<SearchPane, SearchPaneSuggestionsRequestedEventArgs>(OnSearchPaneSuggestionsRequested);
        }


        /// <summary>
        /// Modèle d'affichage décrivant l'un des filtres disponibles pour l'affichage des résultats de recherche.
        /// </summary>
        private sealed class Filter : InterfaceXAML.Common.BindableBase
        {
            private String _name;
            private int _count;
            private bool _active;

            public Filter(String name, int count, bool active = false)
            {
                this.Name = name;
                this.Count = count;
                this.Active = active;
            }

            public override String ToString()
            {
                return Description;
            }

            public String Name
            {
                get { return _name; }
                set { if (this.SetProperty(ref _name, value)) this.OnPropertyChanged("Description"); }
            }

            public int Count
            {
                get { return _count; }
                set { if (this.SetProperty(ref _count, value)) this.OnPropertyChanged("Description"); }
            }

            public bool Active
            {
                get { return _active; }
                set { this.SetProperty(ref _active, value); }
            }

            public String Description
            {
                get { return String.Format("{0} ({1})", _name, _count); }
            }
        }
    }
}
